
import json
import tkinter as tk
from tkinter import filedialog, messagebox, ttk
from pptx import Presentation
from pptx.util import Inches, Pt
import threading

class JsonToPptApp:
    def __init__(self):
        self.window = tk.Tk()
        self.window.title("JSON转PPT工具 v1.0")
        self.window.geometry("600x400")
        self.setup_ui()
        self.converting = False
        
    def setup_ui(self):
        # 主框架
        main_frame = tk.Frame(self.window, padx=20, pady=15)
        main_frame.pack(fill=tk.BOTH, expand=True)
        
        # 输入文件选择
        input_frame = tk.LabelFrame(main_frame, text="输入设置", padx=10, pady=10)
        input_frame.pack(fill=tk.X, pady=5)
        
        tk.Label(input_frame, text="JSON文件:").pack(anchor=tk.W)
        self.json_entry = tk.Entry(input_frame)
        self.json_entry.pack(fill=tk.X, pady=5)
        tk.Button(input_frame, text="浏览...", command=self.select_json).pack(anchor=tk.E)
        
        # 输出设置
        output_frame = tk.LabelFrame(main_frame, text="输出设置", padx=10, pady=10)
        output_frame.pack(fill=tk.X, pady=5)
        
        tk.Label(output_frame, text="PPT输出路径:").pack(anchor=tk.W)
        self.ppt_entry = tk.Entry(output_frame)
        self.ppt_entry.pack(fill=tk.X, pady=5)
        tk.Button(output_frame, text="浏览...", command=self.select_ppt).pack(anchor=tk.E)
        
        # 进度显示
        progress_frame = tk.Frame(main_frame)
        progress_frame.pack(fill=tk.X, pady=10)
        
        self.progress = ttk.Progressbar(progress_frame, orient=tk.HORIZONTAL, mode='determinate')
        self.progress.pack(fill=tk.X)
        self.status_label = tk.Label(progress_frame, text="准备就绪")
        self.status_label.pack(anchor=tk.W)
        
        # 操作按钮
        btn_frame = tk.Frame(main_frame)
        btn_frame.pack(fill=tk.X, pady=5)
        
        tk.Button(btn_frame, text="开始转换", command=self.start_conversion).pack(side=tk.LEFT, padx=5)
        tk.Button(btn_frame, text="取消", command=self.cancel_conversion).pack(side=tk.LEFT, padx=5)
        tk.Button(btn_frame, text="退出", command=self.window.quit).pack(side=tk.RIGHT)
    
    def select_json(self):
        path = filedialog.askopenfilename(filetypes=[("JSON文件", "*.json")])
        if path:
            self.json_entry.delete(0, tk.END)
            self.json_entry.insert(0, path)
    
    def select_ppt(self):
        path = filedialog.asksaveasfilename(
            defaultextension=".pptx",
            filetypes=[("PowerPoint文件", "*.pptx")]
        )
        if path:
            self.ppt_entry.delete(0, tk.END)
            self.ppt_entry.insert(0, path)
    
    def start_conversion(self):
        if self.converting:
            return
            
        json_path = self.json_entry.get()
        ppt_path = self.ppt_entry.get()
        
        if not json_path or not ppt_path:
            messagebox.showerror("错误", "请选择输入和输出路径")
            return
            
        self.converting = True
        self.progress["value"] = 0
        self.status_label.config(text="正在转换...")
        
        threading.Thread(
            target=self.convert_json_to_ppt,
            args=(json_path, ppt_path),
            daemon=True
        ).start()
    
    def convert_json_to_ppt(self, json_path, ppt_path):
        try:
            with open(json_path, 'r', encoding='utf-8') as f:
                data = json.load(f)
            
            prs = Presentation()
            slide_layouts = prs.slide_layouts
            
            # 添加标题幻灯片
            title_slide = prs.slides.add_slide(slide_layouts[0])
            title_slide.shapes.title.text = data.get('title', '演示文稿')
            if 'subtitle' in data:
                title_slide.placeholders[1].text = data['subtitle']
            
            self.update_progress(30)
            
            # 处理内容幻灯片
            for i, slide_data in enumerate(data.get('slides', [])):
                if not self.converting:
                    break
                    
                slide_type = slide_data.get('type', 'text')
                title = slide_data.get('title', '')
                
                if slide_type == 'text':
                    slide = prs.slides.add_slide(slide_layouts[1])
                    slide.shapes.title.text = title
                    
                    textbox = slide.shapes.add_textbox(
                        Inches(1), Inches(1.5), Inches(8), Inches(4.5)
                    )
                    tf = textbox.text_frame
                    
                    for item in slide_data.get('content', []):
                        p = tf.add_paragraph()
                        if isinstance(item, str):
                            p.text = item
                        elif isinstance(item, dict):
                            p.text = item.get('text', '')
                            p.level = item.get('level', 0)
                
                elif slide_type == 'table':
                    slide = prs.slides.add_slide(slide_layouts[5])
                    slide.shapes.title.text = title
                    
                    table_data = slide_data.get('data', [])
                    rows = len(table_data)
                    cols = len(table_data[0]) if rows > 0 else 0
                    
                    table = slide.shapes.add_table(
                        rows, cols, Inches(1), Inches(1.5), Inches(8), Inches(4.5)
                    ).table
                    
                    for r, row in enumerate(table_data):
                        for c, cell in enumerate(row):
                            table.cell(r, c).text = str(cell)
                
                self.update_progress(30 + (i+1)*60/len(data['slides']))
            
            if self.converting:
                prs.save(ppt_path)
                self.window.after(0, lambda: messagebox.showinfo(
                    "完成", f"PPT已成功保存到:\n{ppt_path}"
                ))
        
        except Exception as e:
            self.window.after(0, lambda: messagebox.showerror(
                "错误", f"转换失败:\n{str(e)}"
            ))
        
        finally:
            self.converting = False
            self.update_progress(0)
            self.status_label.config(text="转换完成" if self.converting else "准备就绪")
    
    def update_progress(self, value):
        self.window.after(0, lambda: self.progress.config(value=value))
    
    def cancel_conversion(self):
        if self.converting:
            if messagebox.askyesno("确认", "确定要取消当前转换吗？"):
                self.converting = False
                self.status_label.config(text="转换已取消")
    
    def run(self):
        self.window.mainloop()

if __name__ == "__main__":
    app = JsonToPptApp()
    app.run()
